﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using System.ComponentModel;

namespace Jemgine.Engine
{
	public class Physics : EntityComponent
	{
		[Microsoft.Xna.Framework.Content.ContentSerializerIgnore]
		protected Box2D.XNA.Body _physicsBody = null;

        public float Mass { get; set; }

        public override void SetActive(bool Active)
        {
            base.SetActive(Active);
            if (PhysicsBody != null) PhysicsBody.SetActive(Active);
        }

		[Microsoft.Xna.Framework.Content.ContentSerializerIgnore
#if (!XBOX)
		,System.ComponentModel.Browsable(false)
#endif
		]
		public Box2D.XNA.Body PhysicsBody { get { return _physicsBody; } }

		public bool IsBullet { get; set; }
		public bool AffectedByGravity { get; set; }

		public float Friction { get; set; }
		public float LinearDamping { get; set; }

        [ContentSerializer(Optional = true)]
        public bool AllowSleep { get; set; }

		public enum CollisionGroups
		{
			World = 1,
			Player = -2,
			Enemy = 3,
            Meta = 4,
		}

		public CollisionGroups CollisionGroup { get; set; }

		public void SetCollisionGroup(CollisionGroups Group)
		{
			//TODO : Use SetCollisionGroup for all collision group changes, including initial setup.
			//TODO : More collision groups, such as PlayerClip, HeldObject, etc.
			for (Box2D.XNA.Fixture Fixture = PhysicsBody.GetFixtureList(); Fixture != null; Fixture = Fixture.GetNext())
			{
				Box2D.XNA.Filter Filter;
				Fixture.GetFilterData(out Filter);
				Filter.groupIndex = (short)Group;
				Fixture.SetFilterData(ref Filter);
			}
		}

        public Vector2 Gravity { get; set; }

        public void SetGravity(Vector2 Gravity)
        {
            if (AffectedByGravity)
            {
                this.Gravity = Gravity;
                if (_physicsBody != null) _physicsBody.Gravity = Gravity;
            }
        }

		public Physics()
		{
			CollisionGroup = CollisionGroups.World;
			AffectedByGravity = true;
			IsBullet = false;
			Friction = 0.0f;
			LinearDamping = 0.0f;
            Gravity = new Vector2(0, -80);
            AllowSleep = true;
            Mass = 1;

            AddOutput("OnContact", typeof(Data.EntityRecord));
		}

        public virtual void OnContact(Physics E, Vector2 A, Vector2 B)
        {
            OutputTerminals[0].Fire(new Data.ScriptPayload { SenderRef = E.Me, Physics = E });
        }

		public override void _Destroy()
		{
			Me.Sim.GetModule<PhysicsModule>().PhysicsSimulator.DestroyBody(_physicsBody);
		}

        public bool TestPoint(Vector2 Point)
        {
            if (_physicsBody == null) return false;

            for (var Fixture = _physicsBody.GetFixtureList(); Fixture != null; Fixture = Fixture.GetNext())
                if (Fixture.TestPoint(Point)) return true;

            return false;
        }

        public override void Reset(EntityComponent To)
        {
            base.Reset(To);

            if (PhysicsBody != null)
            {
                PhysicsBody.SetLinearVelocity(Vector2.Zero);
                PhysicsBody.Position = Me.Position;
                PhysicsBody.Rotation = Me.Angle;
                PhysicsBody.SetAwake(true);
            }
        }

        public override void _Initialize(ContentManager Content)
        {
            this.SetActive(Me.Enabled);
        }
    }
}
